package admin

import (
	"context"
	"ia/apps/admin/dto/oin"
	oinadmin "ia/apps/admin/dto/oin/admin"
	ooutadmin "ia/apps/admin/dto/oout/admin"
	"ia/apps/admin/repository/query"
	modeladmin "ia/common/model/admin"
	"ia/common/storage"
	"ia/common/support"
	"ia/common/support/global"
	"strconv"

	"gorm.io/gorm"
)

type AdminUserService interface {
	Create(oinadmin.AdminUserIn) error
	Edit(oinadmin.AdminUserIn) error
	DeleteByIdList([]int64) error
	GetById(int64) (*modeladmin.AdminUser, error)
	GetByUsername(string) (*modeladmin.AdminUser, error)
	ResetPassword(oinadmin.ResetPassword) error
	GetTable(oin.VxeTableIn) ([]*ooutadmin.AdminUserOut, int64, error)
	GetList() ([]*ooutadmin.AdminUserOut, error)
}

func NewAdminlUserService() *adminUserService {
	return &adminUserService{}
}

type adminUserService struct{}

func (impl *adminUserService) Create(in oinadmin.AdminUserIn) (err error) {
	err = storage.GDB1.Transaction(func(tx *gorm.DB) error {
		if err = tx.Create(&in).Error; err != nil {
			return err
		}
		if len(in.Roles) > 0 {
			casbins := make([]*modeladmin.CasbinRule, 0)
			for _, v := range in.Roles {
				casbins = append(casbins, &modeladmin.CasbinRule{
					Ptype: "g",
					V0:    strconv.Itoa(int(in.Id)),
					V1:    strconv.FormatInt(v, 10),
					V2:    global.GConfig.App.Own.Tenant,
				})
			}
			if err = tx.CreateInBatches(casbins, 100).Error; err != nil {
				return err
			}
		}
		return nil
	})
	return
}

func (impl *adminUserService) Edit(in oinadmin.AdminUserIn) (err error) {
	err = storage.GDB1.Transaction(func(tx *gorm.DB) error {
		if err = tx.Omit("password").Save(&in).Error; err != nil {
			return err
		}
		if err = tx.Delete(&modeladmin.CasbinRule{},
			"ptype='g' AND v0=? AND v2=?", in.Id, global.GConfig.App.Own.Tenant).Error; err != nil {
			return err
		}
		if len(in.Roles) > 0 {
			casbins := make([]*modeladmin.CasbinRule, 0)
			for _, v := range in.Roles {
				casbins = append(casbins, &modeladmin.CasbinRule{
					Ptype: "g",
					V0:    strconv.Itoa(int(in.Id)),
					V1:    strconv.FormatInt(v, 10),
					V2:    global.GConfig.App.Own.Tenant,
				})
			}
			if err = tx.CreateInBatches(casbins, 100).Error; err != nil {
				return err
			}
		}
		return nil
	})
	return
}

func (impl *adminUserService) DeleteByIdList(idList []int64) (err error) {
	err = storage.GDB1.Transaction(func(tx *gorm.DB) error {
		if err = tx.Delete(&modeladmin.AdminUser{}, "id in ?", idList).Error; err != nil {
			return err
		}
		if err = tx.Delete(&modeladmin.CasbinRule{}, "ptype='g' AND v0 in ?", idList).Error; err != nil {
			return err
		}
		return nil
	})
	return
}

func (impl *adminUserService) GetById(id int64) (result *modeladmin.AdminUser, err error) {
	err = storage.GDB1.Omit("password").Take(&result, "id=?", id).Error
	return
}

func (impl *adminUserService) GetByUsername(username string) (result *modeladmin.AdminUser, err error) {
	err = storage.GDB1.Take(&result, "username=?", username).Error
	return
}

func (impl *adminUserService) ResetPassword(in oinadmin.ResetPassword) error {
	m := query.Use(storage.GDB1).AdminUserOut
	do := m.WithContext(context.Background())

	// mUser, err := do.Where(m.Id.Eq(in.Id)).Take()
	// if err != nil {
	// 	return err
	// }

	// ckPassword := support.CheckPassword(mUser.Password, in.PasswordOld)
	// if !ckPassword {
	// 	return global.PasswordError
	// }

	newPasswordEncrypt, err := support.EncryptPassword(in.PasswordNew)
	if err != nil {
		return err
	}

	_, err = do.Where(m.Id.Eq(in.Id)).Update(m.Password, newPasswordEncrypt)
	if err != nil {
		return err
	}
	return err
}

func (impl *adminUserService) GetTable(in oin.VxeTableIn) (rows []*ooutadmin.AdminUserOut, total int64, err error) {
	q := query.Use(storage.GDB1).AdminUserOut
	do := q.WithContext(context.Background())

	rows, total, err = do.Omit(q.Password).Preload(q.Org).FindByPage(in.Offset(), in.PageSize)

	for _, v := range rows {
		var roles = make([]*ooutadmin.AdminRoleOut, 0)
		if err = storage.GDB1.Raw(`
		select * from admin_role where id in (
		select v1 from casbin_rule where ptype = 'g' and v0=?
		)`, v.Id).Scan(&roles).Error; err != nil {
			return
		}
		v.Roles = roles
	}
	return
}

func (impl *adminUserService) GetList() (rows []*ooutadmin.AdminUserOut, err error) {
	q := query.Use(storage.GDB1).AdminUserOut
	do := q.WithContext(context.Background())

	rows, err = do.Where(q.Enable.Gt(0)).Find()
	return
}
